// MRTOprt.cpp: implementation of the CMRTOprt class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "MRTObject.h"
#include "MRTOprt.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

BOOL CMRTAdd::Do()
{
	for (int i = 0; i < m_pOprtObjs.GetSize(); i++)
	{
		CMRTObject* pObj = m_pOprtObjs.GetAt(i);
		POSITION pos = m_pAdd->Find(pObj);
		if (pos != NULL)
			m_pAdd->RemoveAt(pos);
		m_pList->AddTail(pObj);
	}
	return TRUE;
}

BOOL CMRTAdd::Undo()
{
	for (int i = 0; i < m_pOprtObjs.GetSize(); i++)
	{
		CMRTObject* pObj = m_pOprtObjs.GetAt(i);
		POSITION posObj = m_pList->Find(pObj);
		if (posObj != NULL)
		{
			m_pList->RemoveAt(posObj);
			m_pAdd->AddTail(pObj);
		}
	}
	return TRUE;
}

BOOL CMRTDel::Do()
{
	for (int i = m_pOprtObjs.GetSize() - 1; i > -1; i--)
	{
		CMRTObject* pObj = m_pOprtObjs.GetAt(i);
		POSITION pos = m_pList->Find(pObj);
		if (pos != NULL)
		{
			m_pList->RemoveAt(pos);
			m_pRemove->AddTail(pObj);
		}
	}

	return TRUE;
}

BOOL CMRTDel::Undo()
{
	m_pList->RemoveAll();
	m_pList->AddTail(&m_lstCopy);
	for (int i = m_pOprtObjs.GetSize() - 1; i > -1; i--)
	{
		CMRTObject* pObj = m_pOprtObjs.GetAt(i);
		POSITION pos = m_pRemove->Find(pObj);
		if (pos != NULL)
			m_pRemove->RemoveAt(pos);
	}
	return TRUE;
}

CMRTMove::CMRTMove(CMRTObject* pMRTObj, LPRECT lpRect) : CMRTOprt(pMRTObj)
{
	m_pRects.Add(new CRect(lpRect));
}

CMRTMove::CMRTMove(CArray<CMRTObject*, CMRTObject*>* pMRTObjs, CArray<CRect*, CRect*>* pRects) : CMRTOprt(pMRTObjs)
{
	for (int i = 0; i < pRects->GetSize(); i++)
	{
		m_pRects.Add(new CRect(pRects->GetAt(i)));
	}
}

BOOL CMRTMove::Do()
{
	BOOL bMoved = FALSE;
	for (int i = 0; i < m_pOprtObjs.GetSize(); i++)
	{
		CMRTObject* pObj = m_pOprtObjs.GetAt(i);
		CRect* pRect = m_pRects.GetAt(i);
		CRect rect = *pRect;
		*pRect = pObj->GetRect();
		pObj->SetRect(rect);
		if (!bMoved)
		{
			rect = pObj->GetRect();
			if (rect != *pRect)
				bMoved = TRUE;
		}
	}

	return bMoved;
}

BOOL CMRTMove::Undo()
{
	return Do();
}

CMRTMove::~CMRTMove()
{
	for (int i = 0; i < m_pRects.GetSize(); i++)
		delete m_pRects.GetAt(i);
}

CMRTGroup::~CMRTGroup()
{
	
}

BOOL CMRTGroup::Do()
{
	CRect rectGroup(0, 0, 0, 0);
	CRect rect;

	POSITION pos = m_pList->GetTailPosition();
	CMRTObjList lstMove;
	CMRTObjList lstOprt;
	
	for (int i = 0; i < m_pOprtObjs.GetSize(); i++)
		lstOprt.AddTail(m_pOprtObjs.GetAt(i));

	POSITION pos1 = NULL;
	for (; pos != NULL;)
	{
		POSITION pos0 = pos;
		CMRTObject* pObj = m_pList->GetPrev(pos);
		if (lstOprt.Find(pObj))
		{
			rect = pObj->GetRect();
			if (lstMove.GetCount())
			{
				if (rect.left < rectGroup.left)
					rectGroup.left = rect.left;
				if (rect.right > rectGroup.right)
					rectGroup.right = rect.right;
				if (rect.top > rectGroup.top)
					rectGroup.top = rect.top;
				if (rect.bottom < rectGroup.bottom)
					rectGroup.bottom = rect.bottom;

				if (pos1 == pos0)
					pos1 = pos;
			}
			else
			{
				rectGroup = rect;
				pos1 = pos;
			}
			lstMove.AddHead(pObj);
			m_pList->RemoveAt(pos0);
		}
	}

	if (lstMove.GetCount())
	{
		if (m_pGroup == NULL)
		{
			m_pGroup = new CMRTObject;
			if (lstOprt.GetTail() != NULL)
				m_pGroup->m_nLayer = lstOprt.GetTail()->m_nLayer;
		}
		else
		{
			pos = m_pAdd->Find(m_pGroup);
			if (pos != NULL)
				m_pAdd->RemoveAt(pos);
		}

		m_pGroup->m_rectPosition = rectGroup;
		pos = lstMove.GetHeadPosition();
		for (; pos != NULL;)
		{
			CMRTObject* pObj = lstMove.GetNext(pos);
			rect = pObj->m_rectPosition;
			pObj->m_rectPosition.left -= rectGroup.left;
			pObj->m_rectPosition.top -= rectGroup.top;
			pObj->m_rectPosition.right = pObj->m_rectPosition.left +
				rect.Width();
			pObj->m_rectPosition.bottom = pObj->m_rectPosition.top +
				rect.Height();
			m_pGroup->m_lstChidren.AddTail(pObj);
		}

		if (pos1 != NULL)
			m_pList->InsertAfter(pos1, m_pGroup);
		else
			m_pList->AddTail(m_pGroup);
		m_pOprtObjs.RemoveAll();
		m_pOprtObjs.Add(m_pGroup);
	}

	return TRUE;
}

BOOL CMRTGroup::Undo()
{
	m_pList->RemoveAll();
	m_pList->AddTail(&m_lstCopy);
	
	CMRTObject* pGroup = m_pOprtObjs.GetAt(0);
	POSITION pos = pGroup->m_lstChidren.GetHeadPosition();
	
	CMRTObject* pChild = NULL;
	CRect rect;
	while (pGroup->m_lstChidren.GetCount())
	{
		pChild = pGroup->m_lstChidren.RemoveHead();
		rect = pChild->m_rectPosition;
		pChild->m_rectPosition.left += pGroup->m_rectPosition.left;
		pChild->m_rectPosition.top += pGroup->m_rectPosition.top;
		pChild->m_rectPosition.right = pChild->m_rectPosition.left + rect.Width();
		pChild->m_rectPosition.bottom = pChild->m_rectPosition.top + rect.Height();
		m_pOprtObjs.Add(pChild);
	}
	m_pOprtObjs.RemoveAt(0);
	m_pAdd->AddTail(pGroup);
	//delete pObj;

	return TRUE;
}

BOOL CMRTUngroup::Do()
{
	CMRTObjArray ungroupObjs;

	CRect rect;

	UINT n = 0;
	m_lstChildren.RemoveAll();
	for (int i = 0; i < m_pOprtObjs.GetSize(); i++)
	{
		CMRTObject* pObj = m_pOprtObjs.GetAt(i);
		if (pObj->m_lstChidren.IsEmpty())
			continue;

		m_lstChildren.AddTail(pObj);
		POSITION pos = m_pList->Find(pObj);
		CMRTObject* pChild = NULL;
		while (pObj->m_lstChidren.GetCount())
		{
			pChild = pObj->m_lstChidren.RemoveHead();
			rect = pChild->m_rectPosition;
			pChild->m_rectPosition.left += pObj->m_rectPosition.left;
			pChild->m_rectPosition.top += pObj->m_rectPosition.top;
			pChild->m_rectPosition.right = pChild->m_rectPosition.left +
				rect.Width();
			pChild->m_rectPosition.bottom = pChild->m_rectPosition.top +
				rect.Height();
			m_pList->InsertAfter(pos, pChild);
			m_lstChildren.AddTail(pChild);
			ungroupObjs.Add(pChild);
		}
		m_pList->RemoveAt(pos);
		m_pGroup->AddTail(pObj);
		//delete pObj;
	}
	m_pOprtObjs.Copy(ungroupObjs);
	return TRUE;
}

BOOL CMRTUngroup::Undo()
{
	CMRTObjArray ungroupObjs;

	CRect rect;
	POSITION pos = m_lstChildren.GetHeadPosition();
	CMRTObject* pGroup = m_lstChildren.GetNext(pos);

	while (pos != NULL)
	{
		CRect rectGroup = pGroup->GetRect();
		for (; pos != NULL;)
		{
			CMRTObject* pObj = m_lstChildren.GetNext(pos);
			if (m_lstCopy.Find(pObj))
			{
				POSITION pos0 = m_pGroup->Find(pGroup);
				if (pos0 != NULL)
					m_pGroup->RemoveAt(pos0);
				ungroupObjs.Add(pGroup);
				pGroup = pObj;
				break;
			}

			rect = pObj->m_rectPosition;
			pObj->m_rectPosition.left -= rectGroup.left;
			pObj->m_rectPosition.top -= rectGroup.top;
			pObj->m_rectPosition.right = pObj->m_rectPosition.left + rect.Width();
			pObj->m_rectPosition.bottom = pObj->m_rectPosition.top + rect.Height();
			pGroup->m_lstChidren.AddTail(pObj);
		}
	}

	if (pGroup != NULL)
	{
		POSITION pos0 = m_pGroup->Find(pGroup);
		if (pos0 != NULL)
			m_pGroup->RemoveAt(pos0);
		ungroupObjs.Add(pGroup);
	}

	m_pOprtObjs.Copy(ungroupObjs);
	m_pList->RemoveAll();
	m_pList->AddTail(&m_lstCopy);

	return TRUE;
}

CMRTProp::CMRTProp(CMRTObject* pMRTObj, DWORD dwProp) : CMRTOprt(pMRTObj)
{
	m_xml.m_bReadOnly = FALSE;
	UINT n = 0;
	if (m_xml.CreateKey(_T("MRTObj%d"), n))
	{
		pMRTObj->Serialize(m_xml);
		m_xml.Back();
	}
	m_dwProp = dwProp;
}

BOOL CMRTProp::Do()
{
	BOOL bModifed = FALSE;
	m_xml.m_bReadOnly = TRUE;
	if (m_xml.Open(_T("NewMRTObj"))) // Redo
	{
		bModifed = TRUE;
		for (int i = 0; i < m_pOprtObjs.GetSize(); i++)
		{
			CMRTObject* pObject = m_pOprtObjs.GetAt(i);
			pObject->Serialize(m_xml, m_dwProp);
		}
					
		m_xml.Back();
	}
	else if (m_pOprtObjs.GetSize())
	{
		m_xml.m_bReadOnly = FALSE;
		UINT n = 1;
		for (; n < m_pOprtObjs.GetSize(); n++)
		{
			CMRTObject* pObject = m_pOprtObjs.GetAt(n);
			if (m_xml.CreateKey(_T("MRTObj%d"), n))
			{
				pObject->Serialize(m_xml);
				m_xml.Back();
			}
		}

		CString strBuffer0;
		m_xml.GetTree()->WriteToBuffer(strBuffer0, 0);

		CXMLSettings xml(FALSE);
		if (m_xml.CreateKey(_T("NewMRTObj")))
		{
			UINT i = 0;		
			CMRTObject* pObject = m_pOprtObjs.GetAt(0);
			pObject->Serialize(m_xml);
			if (xml.CreateKey(_T("MRTObj%d"), i))
			{
				pObject->Serialize(xml);
				xml.Back();
			}
			m_xml.m_bReadOnly = TRUE;
			for (i = 1; i < m_pOprtObjs.GetSize(); i++)
			{
				CMRTObject* pObject = m_pOprtObjs.GetAt(i);
				pObject->Serialize(m_xml, m_dwProp);
				if (xml.CreateKey(_T("MRTObj%d"), i))
				{
					pObject->Serialize(xml);
					xml.Back();
				}
			}
			m_xml.Back();
		}

		CString strBuffer;
		xml.GetTree()->WriteToBuffer(strBuffer, 0);
		bModifed = (strBuffer0 != strBuffer);
	}

	return bModifed;
}

BOOL CMRTProp::Undo()
{
	m_xml.m_bReadOnly = TRUE;
	for (UINT i = 0; i < m_pOprtObjs.GetSize(); i++)
	{
		CMRTObject* pObject = m_pOprtObjs.GetAt(i);
		if (m_xml.Open(_T("MRTObj%d"), i))
		{
			pObject->Serialize(m_xml, m_dwProp);
			m_xml.Back();
		}
	}
	return TRUE;
}

BOOL CMRTReorder::Do()
{
	CMRTObjList lstMove;
	CMRTObjList lstOprt;
	for (int i = 0; i < m_pOprtObjs.GetSize(); i++)
		lstOprt.AddTail(m_pOprtObjs.GetAt(i));

	int nContinued = 0; // Is Continued
	int nStart = 0;		// Continued Start

	POSITION pos = m_pList->GetTailPosition();
	for (int j = 0; pos != NULL; j++)
	{
		POSITION pos0 = pos;
		CMRTObject* pObj = m_pList->GetPrev(pos);
		if (lstOprt.Find(pObj))
		{
			lstMove.AddHead(pObj);
			m_pList->RemoveAt(pos0);
			if (nContinued == 0)
			{
				nStart = j;
				nContinued = 1;
			}
		}
		else if (nContinued == 1)
			nContinued = 2;
	}

	BOOL bReordered = TRUE;
	if (m_lOrder) // SendToBack
	{
		m_pList->AddTail(&lstMove);
		if ((nContinued == 1) && (nStart == 0))
			bReordered = FALSE;
	}
	else // BringToFront
	{
		m_pList->AddHead(&lstMove);
		if ((nContinued == 1) && (nStart == (m_pList->GetCount() - lstMove.GetCount())))
			bReordered = FALSE;
	}

	return bReordered;
}

BOOL CMRTReorder::Undo()
{
	m_pList->RemoveAll();
	m_pList->AddTail(&m_lstCopy);

	return TRUE;
}
